package qc.module.qms.service.pointdata;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsConstant;
import qc.common.core.enums.qms.QmsPointDataQualityEnum;
import qc.common.core.enums.qms.QmsPointTimeSegmentEnum;
import qc.common.core.enums.qms.QmsPointValueFieldEnum;
import qc.common.core.enums.qms.QmsQueryPointDataTimeRangeTypeEnum;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.module.qms.dto.pointdata.QmsPointNumericDataDto;
import qc.module.qms.entity.*;
import qc.module.qms.mapper.QmsPointNumericDataMapper;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * QMS点号数据查询Service，仅提供查询指定点号的数据
 * 查询一个点号，提供定点、top1、指定时间段；可以按数据质量过滤；不提供按指定频次进行插值处理；
 *
 * @author QuCheng Tech
 * @since 2025/8/21
 */
@Service
public class QmsPointDataQueryService {
    private static final Logger logger = LoggerFactory.getLogger(QmsPointDataQueryService.class);

    @Autowired
    private QmsPointRealNumericDataService pointRealNumericDataService;

    @Autowired
    private QmsPointHourNumericDataService pointHourNumericDataService;

    @Autowired
    private QmsPointDayNumericDataService pointDayNumericDataService;

    @Autowired
    private QmsPointWeekNumericDataService pointWeekNumericDataService;

    @Autowired
    private QmsPointTendaysNumericDataService pointTendaysNumericDataService;

    @Autowired
    private QmsPointMonthNumericDataService pointMonthNumericDataService;

    @Autowired
    private QmsPointQuarterNumericDataService pointQuarterNumericDataService;

    @Autowired
    private QmsPointYearNumericDataService pointYearNumericDataService;

    /**
     * 查询指定点号指定时间段内数据，每条数据包含完整信息；包含起止时间点，不管数据质量，全部记录均返回
     *
     * @param pointid   点号
     * @param tmseg     时段类型
     * @param beginTime 起始时间
     * @param endTime   截止时间
     * @return java.util.List<qc.module.qms.dto.pointdata.QmsPointNumericDataDto>
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public List<QmsPointNumericDataDto> query(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime beginTime, LocalDateTime endTime) {
        return query(pointid, tmseg, beginTime, endTime, false, false, QmsPointDataQualityEnum.UN_DEFINE);
    }

    /**
     * 查询指定点号指定时间段内数据，每条数据包含完整信息；不管数据质量，全部记录均返回
     *
     * @param pointid          点号
     * @param tmseg            时段类型
     * @param beginTime        起始时间
     * @param endTime          截止时间
     * @param excludeBeginTime 不包含起始时间点
     * @param excludeEndTime   不包含截止时间点
     * @return java.util.List<qc.module.qms.dto.pointdata.QmsPointNumericDataDto>
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public List<QmsPointNumericDataDto> query(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime beginTime, LocalDateTime endTime,
                                              boolean excludeBeginTime, boolean excludeEndTime) {
        return query(pointid, tmseg, beginTime, endTime, excludeBeginTime, excludeEndTime, QmsPointDataQualityEnum.UN_DEFINE);
    }

    /**
     * 查询指定点号指定时间段内数据，每条数据包含完整信息
     *
     * @param pointid          点号
     * @param tmseg            时段类型
     * @param beginTime        起始时间
     * @param endTime          截止时间
     * @param excludeBeginTime 不包含起始时间点
     * @param excludeEndTime   不包含截止时间点
     * @param quality          质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @return java.util.List<qc.module.qms.dto.pointdata.QmsPointNumericDataDto>
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public List<QmsPointNumericDataDto> query(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime beginTime, LocalDateTime endTime,
                                              boolean excludeBeginTime, boolean excludeEndTime, QmsPointDataQualityEnum quality) {
        //根据不同的点号时段类型调用不同的service进行数据查询
        switch (tmseg) {
            case REAL:
            case MINUTE:
                //实时和分钟均当做实时点号
                List<QmsPointRealNumericData> realEns = pointRealNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (realEns != null && realEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.realEntitiesToDtoPointList(realEns);
                else
                    return null;
            case HOUR:
                List<QmsPointHourNumericData> hourEns = pointHourNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (hourEns != null && hourEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.hourEntitiesToDtoList(hourEns);
                else
                    return null;
            case DAY:
                List<QmsPointDayNumericData> dayEns = pointDayNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (dayEns != null && dayEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.dayEntitiesToDtoList(dayEns);
                else
                    return null;
            case WEEK:
                List<QmsPointWeekNumericData> weekEns = pointWeekNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (weekEns != null && weekEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.weekEntitiesToDtoList(weekEns);
                else
                    return null;
            case TEN_DAYS:
                List<QmsPointTendaysNumericData> tendaysEns = pointTendaysNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (tendaysEns != null && tendaysEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.tendaysEntitiesToDtoList(tendaysEns);
                else
                    return null;
            case MONTH:
                List<QmsPointMonthNumericData> monthEns = pointMonthNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (monthEns != null && monthEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.monthEntitiesToDtoList(monthEns);
                else
                    return null;
            case QUARTER:
                List<QmsPointQuarterNumericData> quarterEns = pointQuarterNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (quarterEns != null && quarterEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.quarterEntitiesToDtoList(quarterEns);
                else
                    return null;
            case YEAR:
                List<QmsPointYearNumericData> yearEns = pointYearNumericDataService.query(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, quality);
                if (yearEns != null && yearEns.size() > 0x0)
                    return QmsPointNumericDataMapper.MAPPER.yearEntitiesToDtoList(yearEns);
                else
                    return null;
            default:
                break;
        }

        return null;
    }

    /**
     * 获取指定时间点的数据，仅查询指定的时间点，不往前或往后查询数据；不管数据质量;
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto get(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time) {
        return get(pointid, tmseg, time, QmsPointDataQualityEnum.UN_DEFINE);
    }

    /**
     * 获取指定时间点的数据，仅查询指定的时间点，不往前或往后查询数据
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @param quality 质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto get(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointDataQualityEnum quality) {
        //根据不同的点号时段类型调用不同的service进行数据查询
        switch (tmseg) {
            case REAL:
            case MINUTE:
                //实时和分钟均当做实时点号
                QmsPointRealNumericData realEntity = pointRealNumericDataService.get(pointid, time, quality);
                if (realEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.realEntityToPointDto(realEntity);
                else
                    return null;
            case HOUR:
                QmsPointHourNumericData hourEntity = pointHourNumericDataService.get(pointid, time, quality);
                if (hourEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.hourEntityToDto(hourEntity);
                else
                    return null;
            case DAY:
                QmsPointDayNumericData dayEntity = pointDayNumericDataService.get(pointid, time, quality);
                if (dayEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.dayEntityToDto(dayEntity);
                else
                    return null;
            case WEEK:
                QmsPointWeekNumericData weekEntity = pointWeekNumericDataService.get(pointid, time, quality);
                if (weekEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.weekEntityToDto(weekEntity);
                else
                    return null;
            case TEN_DAYS:
                QmsPointTendaysNumericData tendaysEntity = pointTendaysNumericDataService.get(pointid, time, quality);
                if (tendaysEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.tendaysEntityToDto(tendaysEntity);
                else
                    return null;
            case MONTH:
                QmsPointMonthNumericData monthEntity = pointMonthNumericDataService.get(pointid, time, quality);
                if (monthEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.monthEntityToDto(monthEntity);
                else
                    return null;
            case QUARTER:
                QmsPointQuarterNumericData quarterEntity = pointQuarterNumericDataService.get(pointid, time, quality);
                if (quarterEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.quarterEntityToDto(quarterEntity);
                else
                    return null;
            case YEAR:
                QmsPointYearNumericData yearEntity = pointYearNumericDataService.get(pointid, time, quality);
                if (yearEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.yearEntityToDto(yearEntity);
                else
                    return null;
            default:
                break;
        }

        return null;
    }

    /**
     * 获取小于指定时间点最新一条数据，不管数据质量
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/10/4
     */
    public QmsPointNumericDataDto getLessThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time) {
        return getLessThan(pointid, tmseg, time, QmsPointDataQualityEnum.UN_DEFINE);
    }

    /**
     * 获取小于指定时间点最新一条数据
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @param quality 质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/10/4
     */
    public QmsPointNumericDataDto getLessThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointDataQualityEnum quality) {
        return getNoMoreThan(pointid, tmseg, time, quality, true);
    }

    /**
     * 获取不大于指定时间点最新一条数据；不管数据质量
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto getNoMoreThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time) {
        return getNoMoreThan(pointid, tmseg, time, QmsPointDataQualityEnum.UN_DEFINE);
    }

    /**
     * 获取不大于指定时间点最新一条数据
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @param quality 质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto getNoMoreThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointDataQualityEnum quality) {
        return getNoMoreThan(pointid, tmseg, time, quality, false);
    }

    /**
     * 获取不大于指定时间点最新一条数据
     *
     * @param pointid      点号
     * @param tmseg        时段类型
     * @param time         时间点
     * @param quality      质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @param notEqualTime 时间点不等于，为true时 tm ＜ time，为false时 tm ≤ time
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto getNoMoreThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointDataQualityEnum quality, boolean notEqualTime) {
        //根据不同的点号时段类型调用不同的service进行数据查询
        switch (tmseg) {
            case REAL:
            case MINUTE:
                //实时和分钟均当做实时点号
                QmsPointRealNumericData realEntity = pointRealNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (realEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.realEntityToPointDto(realEntity);
                else
                    return null;
            case HOUR:
                QmsPointHourNumericData hourEntity = pointHourNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (hourEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.hourEntityToDto(hourEntity);
                else
                    return null;
            case DAY:
                QmsPointDayNumericData dayEntity = pointDayNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (dayEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.dayEntityToDto(dayEntity);
                else
                    return null;
            case WEEK:
                QmsPointWeekNumericData weekEntity = pointWeekNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (weekEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.weekEntityToDto(weekEntity);
                else
                    return null;
            case TEN_DAYS:
                QmsPointTendaysNumericData tendaysEntity = pointTendaysNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (tendaysEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.tendaysEntityToDto(tendaysEntity);
                else
                    return null;
            case MONTH:
                QmsPointMonthNumericData monthEntity = pointMonthNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (monthEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.monthEntityToDto(monthEntity);
                else
                    return null;
            case QUARTER:
                QmsPointQuarterNumericData quarterEntity = pointQuarterNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (quarterEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.quarterEntityToDto(quarterEntity);
                else
                    return null;
            case YEAR:
                QmsPointYearNumericData yearEntity = pointYearNumericDataService.getNoMoreThan(pointid, time, quality, notEqualTime);
                if (yearEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.yearEntityToDto(yearEntity);
                else
                    return null;
            default:
                break;
        }

        return null;
    }

    /**
     * 获取大于指定时间点最新一条数据，不管数据质量
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/10/4
     */
    public QmsPointNumericDataDto getMoreThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time) {
        return getMoreThan(pointid, tmseg, time, QmsPointDataQualityEnum.UN_DEFINE);
    }

    /**
     * 获取大于指定时间点最新一条数据
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @param quality 质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/10/4
     */
    public QmsPointNumericDataDto getMoreThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointDataQualityEnum quality) {
        return getNoLessThan(pointid, tmseg, time, quality, true);
    }

    /**
     * 获取不小于指定时间点最新一条数据；不管数据质量
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto getNoLessThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time) {
        return getNoLessThan(pointid, tmseg, time, QmsPointDataQualityEnum.UN_DEFINE);
    }

    /**
     * 获取不小于指定时间点最新一条数据
     *
     * @param pointid 点号
     * @param tmseg   时段类型
     * @param time    时间点
     * @param quality 质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto getNoLessThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointDataQualityEnum quality) {
        return getNoLessThan(pointid, tmseg, time, quality, false);
    }

    /**
     * 获取不小于指定时间点最新一条数据
     *
     * @param pointid      点号
     * @param tmseg        时段类型
     * @param time         时间点
     * @param quality      质量标记，传入未定义是表示全部数据，传入其他表示≥该质量的数据
     * @param notEqualTime 时间点不等于，为true时 tm ＞ time，为false时 tm ≥ time
     * @return qc.module.qms.dto.pointdata.QmsPointNumericDataDto
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsPointNumericDataDto getNoLessThan(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointDataQualityEnum quality, boolean notEqualTime) {
        //根据不同的点号时段类型调用不同的service进行数据查询
        switch (tmseg) {
            case REAL:
            case MINUTE:
                //实时和分钟均当做实时点号
                QmsPointRealNumericData realEntity = pointRealNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (realEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.realEntityToPointDto(realEntity);
                else
                    return null;
            case HOUR:
                QmsPointHourNumericData hourEntity = pointHourNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (hourEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.hourEntityToDto(hourEntity);
                else
                    return null;
            case DAY:
                QmsPointDayNumericData dayEntity = pointDayNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (dayEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.dayEntityToDto(dayEntity);
                else
                    return null;
            case WEEK:
                QmsPointWeekNumericData weekEntity = pointWeekNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (weekEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.weekEntityToDto(weekEntity);
                else
                    return null;
            case TEN_DAYS:
                QmsPointTendaysNumericData tendaysEntity = pointTendaysNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (tendaysEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.tendaysEntityToDto(tendaysEntity);
                else
                    return null;
            case MONTH:
                QmsPointMonthNumericData monthEntity = pointMonthNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (monthEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.monthEntityToDto(monthEntity);
                else
                    return null;
            case QUARTER:
                QmsPointQuarterNumericData quarterEntity = pointQuarterNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (quarterEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.quarterEntityToDto(quarterEntity);
                else
                    return null;
            case YEAR:
                QmsPointYearNumericData yearEntity = pointYearNumericDataService.getNoLessThan(pointid, time, quality, notEqualTime);
                if (yearEntity != null)
                    return QmsPointNumericDataMapper.MAPPER.yearEntityToDto(yearEntity);
                else
                    return null;
            default:
                break;
        }

        return null;
    }

    /**
     * 查询时间段内数据（取value字段数值），包含起始和截止时间点的数据
     *
     * @param pointid   点号
     * @param tmseg     时段类型
     * @param beginTime 起始时间点
     * @param endTime   截止时间点
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getRangeValidValues(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime beginTime, LocalDateTime endTime) {
        return this.getRangeValidValues(pointid, tmseg, beginTime, endTime, QmsPointValueFieldEnum.VALUE);
    }

    /**
     * 查询时间段内数据，包含起始和截止时间点的数据
     *
     * @param pointid    点号
     * @param tmseg      时段类型
     * @param beginTime  起始时间点
     * @param endTime    截止时间点
     * @param valueField 查询的数值字段，传入无效时自动设置为value字段
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getRangeValidValues(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime beginTime, LocalDateTime endTime,
                                                          QmsPointValueFieldEnum valueField) {
        return this.getRangeValidValues(pointid, tmseg, beginTime, endTime, valueField, false, false);
    }

    /**
     * 查询时间段内数据（取value字段数值）
     *
     * @param pointid          点号
     * @param tmseg            时段类型
     * @param beginTime        起始时间点
     * @param endTime          截止时间点
     * @param excludeBeginTime 不包含起始时间点
     * @param excludeEndTime   不包含截止时间点
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getRangeValidValues(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime beginTime, LocalDateTime endTime,
                                                          boolean excludeBeginTime, boolean excludeEndTime) {
        return this.getRangeValidValues(pointid, tmseg, beginTime, endTime, QmsPointValueFieldEnum.VALUE, excludeBeginTime, excludeEndTime);
    }

    /**
     * 查询时间段内数据
     *
     * @param pointid          点号
     * @param tmseg            时段类型
     * @param beginTime        起始时间点
     * @param endTime          截止时间点
     * @param valueField       查询的数值字段，传入无效时自动设置为value字段
     * @param excludeBeginTime 不包含起始时间点
     * @param excludeEndTime   不包含截止时间点
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getRangeValidValues(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime beginTime, LocalDateTime endTime,
                                                          QmsPointValueFieldEnum valueField, boolean excludeBeginTime, boolean excludeEndTime) {
        logger.debug("getRangeValidDatas 查询时间段内有效数据，点号[" + pointid + "]，时段类型[" + tmseg.toString()
                + "]，起始时间[" + LocalDateTimeUtil.formatDateTime(beginTime) + "]，截止时间[" + LocalDateTimeUtil.formatDateTime(endTime)
                + "]，数值字段[" + valueField.toString() + "]，不包含起始时间点[" + excludeBeginTime + "]，不包含截止时间点[" + excludeEndTime + "]");

        //查询指定点号时间段内的有效数据，数据质量满足要求
        QmsPointDataQualityEnum dataQuality = QmsConstant.POINT_DATA_VALID_QUALITY_FROM;
        //根据不同的点号时段类型调用不同的service进行数据查询
        switch (tmseg) {
            case REAL:
            case MINUTE:
                //实时和分钟均当做实时点号
                return pointRealNumericDataService.queryValues(pointid, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            case HOUR:
                return pointHourNumericDataService.queryFieldValues(pointid, valueField, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            case DAY:
                return pointDayNumericDataService.queryFieldValues(pointid, valueField, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            case WEEK:
                return pointWeekNumericDataService.queryFieldValues(pointid, valueField, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            case TEN_DAYS:
                return pointTendaysNumericDataService.queryFieldValues(pointid, valueField, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            case MONTH:
                return pointMonthNumericDataService.queryFieldValues(pointid, valueField, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            case QUARTER:
                return pointQuarterNumericDataService.queryFieldValues(pointid, valueField, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            case YEAR:
                return pointYearNumericDataService.queryFieldValues(pointid, valueField, beginTime, endTime, excludeBeginTime, excludeEndTime, dataQuality);
            default:
                break;
        }

        return null;
    }

    /**
     * 查询指定时间点的数据（取value字段数值），只取指定的时间点数据，不往前或往后取数据
     *
     * @param pointid 点号
     * @param tmseg   时段时间
     * @param time    指定的时间点
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time) {
        //查询指定时间点的数据，指定时间点（不往前或往后取数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, QmsPointValueFieldEnum.VALUE, QmsQueryPointDataTimeRangeTypeEnum.POINT_IN_TIME);
    }

    /**
     * 查询指定时间点的数据，只取指定的时间点数据，不往前或往后取数据
     *
     * @param pointid    点号
     * @param tmseg      时段时间
     * @param time       指定的时间点
     * @param valueField 查询的数值字段，传入无效时自动设置为value字段
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsPointValueFieldEnum valueField) {
        //查询指定时间点的数据，指定时间点（不往前或往后取数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, valueField, QmsQueryPointDataTimeRangeTypeEnum.POINT_IN_TIME);
    }

    /**
     * 查询指定时间点最新一条数据（往前和往后取数据取最接近时间点）的数据（取value字段数值），根据传入的是否往前/往后取最新数据，往前和往后取数据时间均不限制
     *
     * @param pointid       点号
     * @param tmseg         时段时间
     * @param time          指定的时间点
     * @param timeRangeType 往前/往后取数据类型，默认为只取指定时间点的数据
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, QmsQueryPointDataTimeRangeTypeEnum timeRangeType) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, QmsPointValueFieldEnum.VALUE, timeRangeType, null, null);
    }

    /**
     * 查询指定时间点最新一条数据（往前和往后取数据取最接近时间点）的数据，根据传入的是否往前/往后取最新数据，往前和往后取数据时间均不限制
     *
     * @param pointid       点号
     * @param tmseg         时段时间
     * @param time          指定的时间点
     * @param valueField    查询的数值字段，传入无效时自动设置为value字段
     * @param timeRangeType 往前/往后取数据类型，默认为只取指定时间点的数据
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         QmsPointValueFieldEnum valueField, QmsQueryPointDataTimeRangeTypeEnum timeRangeType) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, valueField, timeRangeType, null, null);
    }

    /**
     * 查询指定时间点最新一条数据（往前和往后取数据取最接近时间点）的数据（取value字段数值），根据传入的是否往前/往后取最新数据，可以设置往前限制时间，往后取数据不限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param timeRangeType   往前/往后取数据类型，默认为只取指定时间点的数据
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         QmsQueryPointDataTimeRangeTypeEnum timeRangeType, LocalDateTime limitBeforeTime) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, QmsPointValueFieldEnum.VALUE, timeRangeType, limitBeforeTime, null);
    }

    /**
     * 查询指定时间点最新一条数据（往前和往后取数据取最接近时间点）的数据，根据传入的是否往前/往后取最新数据，可以设置往前限制时间，往后取数据不限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param valueField      查询的数值字段，传入无效时自动设置为value字段
     * @param timeRangeType   往前/往后取数据类型，默认为只取指定时间点的数据
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         QmsPointValueFieldEnum valueField, QmsQueryPointDataTimeRangeTypeEnum timeRangeType,
                                                         LocalDateTime limitBeforeTime) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, valueField, timeRangeType, limitBeforeTime, null);
    }

    /**
     * 查询指定时间点往前最近一条数据（取value字段数值），可以设置往前的限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time, LocalDateTime limitBeforeTime) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, QmsPointValueFieldEnum.VALUE, QmsQueryPointDataTimeRangeTypeEnum.LATEST_BEFORE, limitBeforeTime, null);
    }

    /**
     * 查询指定时间点往前最近一条数据，可以设置往前的限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param valueField      查询的数值字段，传入无效时自动设置为value字段
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         QmsPointValueFieldEnum valueField, LocalDateTime limitBeforeTime) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, valueField, QmsQueryPointDataTimeRangeTypeEnum.LATEST_BEFORE, limitBeforeTime, null);
    }

    /**
     * 查询指定时间点最新一条数据（往前和往后取数据取最接近时间点）的数据（取value字段数值），可以同时设置往前/往后的限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @param limitAfterTime  往后取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         LocalDateTime limitBeforeTime, LocalDateTime limitAfterTime) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, QmsPointValueFieldEnum.VALUE, QmsQueryPointDataTimeRangeTypeEnum.POINT_OF_LATE, limitBeforeTime, limitAfterTime);
    }

    /**
     * 查询指定时间点最新一条数据（往前和往后取数据取最接近时间点）的数据，可以同时设置往前/往后的限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param valueField      查询的数值字段，传入无效时自动设置为value字段
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @param limitAfterTime  往后取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         QmsPointValueFieldEnum valueField, LocalDateTime limitBeforeTime,
                                                         LocalDateTime limitAfterTime) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, valueField, QmsQueryPointDataTimeRangeTypeEnum.POINT_OF_LATE, limitBeforeTime, limitAfterTime);
    }

    /**
     * 查询指定时间点的数据（取value字段数值），根据传入的是否往前/往后取最新数据，可以同时设置往前/往后的限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param timeRangeType   往前/往后取数据类型，默认为只取指定时间点的数据
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @param limitAfterTime  往后取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         QmsQueryPointDataTimeRangeTypeEnum timeRangeType, LocalDateTime limitBeforeTime,
                                                         LocalDateTime limitAfterTime) {
        //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
        return getPointValidValue(pointid, tmseg, time, QmsPointValueFieldEnum.VALUE, QmsQueryPointDataTimeRangeTypeEnum.POINT_OF_LATE, limitBeforeTime, limitAfterTime);
    }

    /**
     * 查询指定时间点的数据，根据传入的是否往前/往后取最新数据，可以同时设置往前/往后的限制时间
     *
     * @param pointid         点号
     * @param tmseg           时段时间
     * @param time            指定的时间点
     * @param valueField      查询的数值字段，传入无效时自动设置为value字段
     * @param timeRangeType   往前/往后取数据类型，默认为只取指定时间点的数据
     * @param limitBeforeTime 往前取数据的限制时间，为null表示不限制
     * @param limitAfterTime  往后取数据的限制时间，为null表示不限制
     * @return java.util.Map<java.time.LocalDateTime, java.lang.Double>
     * @author QuCheng Tech
     * @since 2025/9/24
     */
    public Map<LocalDateTime, Double> getPointValidValue(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime time,
                                                         QmsPointValueFieldEnum valueField, QmsQueryPointDataTimeRangeTypeEnum timeRangeType,
                                                         LocalDateTime limitBeforeTime, LocalDateTime limitAfterTime) {
        logger.debug("getPointValidData 获取指定时间点有效数据，点号[" + pointid + "]，时段类型[" + tmseg.toString()
                + "]，时间点[" + LocalDateTimeUtil.formatDateTime(time) + "]，取时间点类型[" + timeRangeType.toString()
                + "]，数值字段[" + valueField.toString() + "]，往前限制时间[" + limitBeforeTime + "]，往后限制时间[" + limitAfterTime + "]");
        //如果传入的点号或时段类型错误不查询数据
        if (StringUtils.isNotBlank(pointid) && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            //查询指定时间点最近一条数据（往前或往后取最接近时间的数据），数据质量满足要求
            QmsPointDataQualityEnum dataQuality = QmsConstant.POINT_DATA_VALID_QUALITY_FROM;
            //如果传入的查询点号数据时间点类型不为指定时间点、时间点最近、时间点往前最近，自动设置为指定时间点
            if (timeRangeType != QmsQueryPointDataTimeRangeTypeEnum.POINT_IN_TIME && timeRangeType != QmsQueryPointDataTimeRangeTypeEnum.POINT_OF_LATE && timeRangeType != QmsQueryPointDataTimeRangeTypeEnum.LATEST_BEFORE)
                timeRangeType = QmsQueryPointDataTimeRangeTypeEnum.POINT_IN_TIME;
            //如果传入的查询字段不为值字段，自动设置为value字段
            if (valueField == QmsPointValueFieldEnum.MAX_TIME || valueField == QmsPointValueFieldEnum.MIN_TIME)
                valueField = QmsPointValueFieldEnum.VALUE;

            //如果查询为指定时间点，不往前或往后取数据，仅查询传入的时间点数据
            if (timeRangeType == QmsQueryPointDataTimeRangeTypeEnum.POINT_IN_TIME) {
                //查询到已有指定时间点数据，加入到result后返回；查询不到指定时间点数据，返回null
                //根据不同的点号时段类型调用不同的service进行数据查询
                switch (tmseg) {
                    case REAL:
                    case MINUTE:
                        //实时和分钟均当做实时点号
                        return pointRealNumericDataService.getValue(pointid, time, dataQuality);
                    case HOUR:
                        return pointHourNumericDataService.getFieldValue(pointid, valueField, time, dataQuality);
                    case DAY:
                        return pointDayNumericDataService.getFieldValue(pointid, valueField, time, dataQuality);
                    case WEEK:
                        return pointWeekNumericDataService.getFieldValue(pointid, valueField, time, dataQuality);
                    case TEN_DAYS:
                        return pointTendaysNumericDataService.getFieldValue(pointid, valueField, time, dataQuality);
                    case MONTH:
                        return pointMonthNumericDataService.getFieldValue(pointid, valueField, time, dataQuality);
                    case QUARTER:
                        return pointQuarterNumericDataService.getFieldValue(pointid, valueField, time, dataQuality);
                    case YEAR:
                        return pointYearNumericDataService.getFieldValue(pointid, valueField, time, dataQuality);
                    default:
                        break;
                }
            } else {
                //查询为指定时间点往前最近或者指定时间前后最近；均需要先查询时间点往前最近数据
                Map<LocalDateTime, Double> noMoreThanValue = null;//实际只有至多1个数据返回
                // 根据不同的点号时段类型调用不同的service进行数据查询
                switch (tmseg) {
                    case REAL:
                    case MINUTE:
                        //实时和分钟均当做实时点号
                        noMoreThanValue = pointRealNumericDataService.getNoMoreThanValue(pointid, time, dataQuality);
                        break;
                    case HOUR:
                        noMoreThanValue = pointHourNumericDataService.getNoMoreThanFieldValue(pointid, valueField, time, dataQuality);
                        break;
                    case DAY:
                        noMoreThanValue = pointDayNumericDataService.getNoMoreThanFieldValue(pointid, valueField, time, dataQuality);
                        break;
                    case WEEK:
                        noMoreThanValue = pointWeekNumericDataService.getNoMoreThanFieldValue(pointid, valueField, time, dataQuality);
                        break;
                    case TEN_DAYS:
                        noMoreThanValue = pointTendaysNumericDataService.getNoMoreThanFieldValue(pointid, valueField, time, dataQuality);
                        break;
                    case MONTH:
                        noMoreThanValue = pointMonthNumericDataService.getNoMoreThanFieldValue(pointid, valueField, time, dataQuality);
                        break;
                    case QUARTER:
                        noMoreThanValue = pointQuarterNumericDataService.getNoMoreThanFieldValue(pointid, valueField, time, dataQuality);
                        break;
                    case YEAR:
                        noMoreThanValue = pointYearNumericDataService.getNoMoreThanFieldValue(pointid, valueField, time, dataQuality);
                        break;
                    default:
                        break;
                }
                //判断查询时间点往前最新一条数据，如果数据时间就是查询指定的时间点，直接返回该数据；如果不是指定的时间点，判断如果是查询时间点最近数据还需要查询时间点往后数据进行对比时间
                if (noMoreThanValue != null && noMoreThanValue.size() > 0x0) {
                    if (noMoreThanValue.containsKey(time)) {
                        //有查询的指定时间点的数据，直接返回
                        return noMoreThanValue;
                    }
                }

                //判断如果是往前和往后取最近一条数据，再查询不小于时间点的数据
                if (timeRangeType == QmsQueryPointDataTimeRangeTypeEnum.POINT_OF_LATE) {
                    Map<LocalDateTime, Double> noLessThanValue = null;//实际只有至多1个数据返回
                    // 根据不同的点号时段类型调用不同的service进行数据查询
                    switch (tmseg) {
                        case REAL:
                        case MINUTE:
                            //实时和分钟均当做实时点号
                            noLessThanValue = pointRealNumericDataService.getNoLessThanValue(pointid, time, dataQuality);
                            break;
                        case HOUR:
                            noLessThanValue = pointHourNumericDataService.getNoLessThanFieldValue(pointid, valueField, time, dataQuality);
                            break;
                        case DAY:
                            noLessThanValue = pointDayNumericDataService.getNoLessThanFieldValue(pointid, valueField, time, dataQuality);
                            break;
                        case WEEK:
                            noLessThanValue = pointWeekNumericDataService.getNoLessThanFieldValue(pointid, valueField, time, dataQuality);
                            break;
                        case TEN_DAYS:
                            noLessThanValue = pointTendaysNumericDataService.getNoLessThanFieldValue(pointid, valueField, time, dataQuality);
                            break;
                        case MONTH:
                            noLessThanValue = pointMonthNumericDataService.getNoLessThanFieldValue(pointid, valueField, time, dataQuality);
                            break;
                        case QUARTER:
                            noLessThanValue = pointQuarterNumericDataService.getNoLessThanFieldValue(pointid, valueField, time, dataQuality);
                            break;
                        case YEAR:
                            noLessThanValue = pointYearNumericDataService.getNoLessThanFieldValue(pointid, valueField, time, dataQuality);
                            break;
                        default:
                            break;
                    }
                    //判断查询时间点往后最新一条数据，如果数据时间就是查询指定的时间点，直接返回该数据；
                    if (noLessThanValue != null && noLessThanValue.size() > 0x0) {
                        //往后取数据结果就是指定的时间点，或者往前取数据结果为空；均使用往后取数据的结果
                        if (noMoreThanValue == null || noMoreThanValue.size() < 0x1 || noLessThanValue.containsKey(time)) {
                            //有查询的指定时间点的数据，直接返回
                            return noLessThanValue;
                        }
                        //如果不是指定的时间点，判断如果是查询时间点最近数据还需要查询时间点往后数据进行对比时间
                        if (noMoreThanValue != null && noMoreThanValue.size() > 0x0) {
                            LocalDateTime noMoreThanDataTime = noMoreThanValue.keySet().stream().collect(Collectors.toList()).get(0x0);
                            LocalDateTime noLessThanDataTime = noLessThanValue.keySet().stream().collect(Collectors.toList()).get(0x0);
                            Duration noMoreThanDuration = Duration.between(noMoreThanDataTime, time);
                            Duration noLessThanDuration = Duration.between(time, noLessThanDataTime);
                            //判断相差的总秒数
                            if (noMoreThanDuration.getSeconds() > noLessThanDuration.getSeconds())//往后的数据距离时间点更近
                                return noLessThanValue;
                            else
                                return noMoreThanValue;
                        }
                    }
                }

                if (noMoreThanValue != null && noMoreThanValue.size() > 0x0)
                    return noMoreThanValue;
            }
        }

        return null;
    }
}
